/* ---------------------------------------------------------------------
 *
 * -- Privacy-preserving Sharing of Sensitive information Toolkit (PSST)
 *    (C) Copyright 2010 All Rights Reserved
 *
 * -- PSST routines -- Version 1.0.1 -- April, 2010
 * RSA_APSI_OPT corresponds to protocol DT10-APSI in the paper
 *
 * Author         : Yanbin Lu
 * Security and Privacy Research Outfit (SPROUT),
 * University of California, Irvine
 *
 * -- Bug report: send email to yanbinl@uci.edu
 * ---------------------------------------------------------------------
 *
 * -- Copyright notice and Licensing terms:
 *
 *  Redistribution  and  use in  source and binary forms, with or without
 *  modification, are  permitted provided  that the following  conditions
 *  are met:
 *
 * 1. Redistributions  of  source  code  must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce  the above copyright
 *    notice,  this list of conditions, and the  following disclaimer in
 *    the documentation and/or other materials provided with the distri-
 *    bution.
 * 3. The name of the University,  the SPROUT group,  or the names of its
 *    authors  may not be used to endorse or promote products deri-
 *    ved from this software without specific written permission.
 *
 * -- Disclaimer:
 *
 * THIS  SOFTWARE  IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,  INCLUDING,  BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,  INDIRECT, INCIDENTAL, SPE-
 * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO,  PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEO-
 * RY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT  (IN-
 * CLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "rsa_apsi_opt_client.h"
#include "crypto_tool.h"
#include "basic_tool.h"
#include "mpz_tool.h"

RSA_APSI_OPT_Client::RSA_APSI_OPT_Client()
{
  m_g = Memreuse::New();
  m_n = Memreuse::New();
  m_n4 = Memreuse::New();
  m_e = Memreuse::New();
  m_x = Memreuse::New();
  m_Rc = Memreuse::New();
  m_pch = Memreuse::New();
  m_pch_star = Memreuse::New();
  m_d = Memreuse::New();
}

void RSA_APSI_OPT_Client::LoadData()
{
  m_set.clear();
  m_rawset.clear();

  ifstream infile(m_strInputFile.c_str());
  if (!infile)
	{
	  cerr<<"open "<<m_strInputFile<<" error"<<endl;
	  return;
	}
  string element;
  while (getline(infile, element) && infile.good())
	{
	  m_rawset.push_back(element);
	  mpz_t * e = Memreuse::New();
	  CryptoTool::FDH(e, element, m_n);
	  m_set.push_back(e);
	}
}

// for preset parameters 
void RSA_APSI_OPT_Client::Setup(int nbits)
{

  stringstream keyfile;
  keyfile<<"rsa."<<nbits<<".priv";
  BasicTool::Load_RSA_Priv_Key(keyfile.str(), m_rsa);
  m_n = m_rsa->n;
  m_g = m_rsa->g;
  //BasicTool::Load_RSA_Priv_Key(keyfile.str(), m_d, m_e, m_n, m_g);
  LoadData();
  m_n4 = m_rsa->order;
  for (size_t i = 0; i < m_set.size(); i++)
    {
      mpz_t * sig = Memreuse::New();
	  CryptoTool::RsaSig(sig, m_set[i], m_rsa);
      //CryptoTool::RsaSig(sig, m_set[i], m_d, m_n);
      m_vecSig.push_back(sig);
    }
  rn.Initialize(nbits);
}


void RSA_APSI_OPT_Client::Initialize(int nbits)
{
}

int RSA_APSI_OPT_Client::Request1(vector<string>& output)
{
  // compute M_PCH
  mpz_set_ui(*m_pch, 1);
  mpz_set_ui(*m_pch_star, 1);
  for (size_t i = 0; i < m_set.size(); i++)
    {
      mpz_mul(*m_pch, *m_pch, *m_set[i]);
      mpz_mod(*m_pch, *m_pch, *m_n);
      
      mpz_t * sig = m_vecSig[i];
      mpz_mul(*m_pch_star, *m_pch_star, *sig);
      mpz_mod(*m_pch_star, *m_pch_star, *m_n);
    }

  mpz_t * X = Memreuse::New();
  rn.Get_Z_Range(m_Rc, m_n4);
  mpz_powm(*X, *m_g, *m_Rc, *m_n); // g^Rc
  mpz_mul(*X, *m_pch_star, *X);    // X=PCH^*g^Rc
  mpz_mod(*X, *X, *m_n);
  output.push_back(MpzTool::Mpz_to_string(X));
  mpz_t * pchi = Memreuse::New();
  mpz_t * yi = Memreuse::New();
  mpz_t * inva = Memreuse::New();
  mpz_t * rci;

  for (size_t i = 0; i < m_set.size(); i++)
    {
	  rci = Memreuse::New();
      mpz_invert(*inva, *m_vecSig[i], *m_n);
      mpz_mul(*pchi, *m_pch_star, *inva);
      mpz_mod(*pchi, *pchi, *m_n);
      rn.Get_Z_Range(rci, m_n4);
      m_vecRc.push_back(rci);
      mpz_powm(*yi, *m_g, *rci, *m_n); // 
      mpz_mul(*yi, *pchi, *yi);        // PCH_i*g^Rci
	  mpz_mod(*yi, *yi, *m_n);
      output.push_back(MpzTool::Mpz_to_string(yi));
    }
  Memreuse::Delete(pchi);
  Memreuse::Delete(yi);
  Memreuse::Delete(inva);
  Memreuse::Delete(rci);
  Memreuse::Delete(X);
  return 0;
}

int RSA_APSI_OPT_Client::OnResponse1(const vector<string>& input)
{
  m_vecResult.clear();
  mpz_t * Z = Memreuse::New();
  mpz_t * yi = Memreuse::New();
  mpz_t * tip = Memreuse::New();
  mpz_t * ZR = Memreuse::New();
  MpzTool::Mpz_from_string(Z, input[0]);
  size_t i = 0;
  mpz_powm(*ZR, *Z, *m_Rc, *m_n);
  for (i = 0; i < m_set.size(); i++)
    {
      MpzTool::Mpz_from_string(yi, input[i+1]);
      mpz_powm(*tip, *Z, *m_vecRc[i], *m_n);
      mpz_invert(*tip, *tip, *m_n);
      mpz_mul(*tip, *yi, *tip);
	  mpz_mod(*tip, *tip, *m_n);
      mpz_mul(*tip, *ZR, *tip);
	  mpz_mod(*tip, *tip, *m_n);
      m_mapTp[CryptoTool::Hash(tip)] = i;
    }
  map<string,size_t>::iterator it;
  for (; i < input.size(); i++)
    {
      if ((it = m_mapTp.find(input[i])) != m_mapTp.end())
        {
          m_vecResult.push_back(it->second);
        }
    }
  return 0;
}

